#include "core/ServiceFactory.h"
#include <gtest/gtest.h>
#include <fstream>
#include <filesystem>
#include <thread>

class LoggerServiceTest : public ::testing::Test {
protected:
    void SetUp() override {
        logger = dynamic_cast<core::LoggerService*>(
            core::ServiceFactory::createLoggerService("TestLogger").release()
        );
        testLogFile = "test_log.txt";
    }

    void TearDown() override {
        delete logger;
        if (std::filesystem::exists(testLogFile)) {
            std::filesystem::remove(testLogFile);
        }
    }

    core::LoggerService* logger = nullptr;
    std::string testLogFile;
};

TEST_F(LoggerServiceTest, ShouldInitialize) {
    ASSERT_NE(logger, nullptr);
    EXPECT_EQ(logger->getName(), "TestLogger");
}

TEST_F(LoggerServiceTest, ShouldLogMessages) {
    testing::internal::CaptureStdout();
    logger->log("Test message");
    std::string output = testing::internal::GetCapturedStdout();
    
    EXPECT_TRUE(output.find("Test message") != std::string::npos);
    EXPECT_TRUE(output.find("[INFO]") != std::string::npos);
}

TEST_F(LoggerServiceTest, ShouldSupportLogLevels) {
    logger->setLogLevel(core::LogLevel::WARNING);
    
    testing::internal::CaptureStdout();
    logger->debug("Debug message");
    logger->info("Info message");
    logger->warning("Warning message");
    logger->error("Error message");
    std::string output = testing::internal::GetCapturedStdout();
    
    EXPECT_TRUE(output.find("Debug message") == std::string::npos);
    EXPECT_TRUE(output.find("Info message") == std::string::npos);
    EXPECT_TRUE(output.find("Warning message") != std::string::npos);
    EXPECT_TRUE(output.find("Error message") != std::string::npos);
}

TEST_F(LoggerServiceTest, ShouldLogToFile) {
    ASSERT_TRUE(logger->initialize(testLogFile));
    logger->setFileOutputEnabled(true);
    logger->setConsoleOutputEnabled(false);
    
    logger->info("File log message");
    
    std::ifstream file(testLogFile);
    std::string content((std::istreambuf_iterator<char>(file)), 
                       std::istreambuf_iterator<char>());
    
    EXPECT_TRUE(content.find("File log message") != std::string::npos);
}

TEST_F(LoggerServiceTest, ShouldBeThreadSafe) {
    auto logThread = [this](int id) {
        for (int i = 0; i < 100; ++i) {
            logger->info("Thread " + std::to_string(id) + " message " + std::to_string(i));
        }
    };
    
    std::thread t1(logThread, 1);
    std::thread t2(logThread, 2);
    
    t1.join();
    t2.join();
    
    // No crash means thread safety is working
}

TEST_F(LoggerServiceTest, ShouldSupportCustomFormat) {
    logger->setLogFormat("%n - %l: %m (%d)");
    
    testing::internal::CaptureStdout();
    logger->info("Test message");
    std::string output = testing::internal::GetCapturedStdout();
    
    EXPECT_TRUE(output.find("TestLogger - INFO: Test message") != std::string::npos);
    EXPECT_TRUE(output.find("(") != std::string::npos);
    EXPECT_TRUE(output.find(")") != std::string::npos);
}

TEST_F(LoggerServiceTest, ShouldHandleAllPlaceholders) {
    logger->setLogFormat("%d|%l|%n|%m");
    
    testing::internal::CaptureStdout();
    logger->warning("Placeholder test");
    std::string output = testing::internal::GetCapturedStdout();
    
    std::vector<std::string> parts;
    size_t pos = 0;
    while ((pos = output.find("|")) != std::string::npos) {
        parts.push_back(output.substr(0, pos));
        output.erase(0, pos + 1);
    }
    parts.push_back(output);
    
    EXPECT_EQ(parts.size(), 4);
    EXPECT_EQ(parts[1], "WARNING");
    EXPECT_EQ(parts[2], "TestLogger");
    EXPECT_EQ(parts[3], "Placeholder test");
}

TEST_F(LoggerServiceTest, ShouldSupportFormattedLogging) {
    testing::internal::CaptureStdout();
    logger->infof("Formatted %s %d %.2f", "test", 123, 3.14159);
    std::string output = testing::internal::GetCapturedStdout();
    
    EXPECT_TRUE(output.find("Formatted test 123 3.14") != std::string::npos);
}

TEST_F(LoggerServiceTest, ShouldHandleLongFormattedMessages) {
    testing::internal::CaptureStdout();
    logger->warningf("Long string: %01000d", 1);  // 1000 characters
    std::string output = testing::internal::GetCapturedStdout();
    
    EXPECT_TRUE(output.find("0000000001") != std::string::npos);
    EXPECT_LT(output.size(), 2000);  // Check buffer limitation
}

TEST_F(LoggerServiceTest, ShouldHandleSpecialCharacters) {
    testing::internal::CaptureStdout();
    logger->errorf("Special chars: %% %c %x \\n \\t \\\\",  255);
    std::string output = testing::internal::GetCapturedStdout();
    
    // Test all special characters
    EXPECT_TRUE(output.find("Special chars: % $ ff") != std::string::npos);
    EXPECT_TRUE(output.find("\n") != std::string::npos);
    EXPECT_TRUE(output.find("\t") != std::string::npos);
    EXPECT_TRUE(output.find("\\") != std::string::npos);
    
    // Test the full formatted string
    std::string expected = "Special chars: % $ ff \n \t \\";
    EXPECT_TRUE(output.find(expected) != std::string::npos);
}